package viper.call.common;
/*
 * @(#)LiveStream.java	1.4 01/03/13
 *
 * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

/*****************************************
 * LiveStream.java
 * ----------------
 * Revision: v.1.0
 * Author: Ji Kim
 * Date Created: 12/13/2009
 * Description:
 * Last Back-Up:
 * Revision History: *Modified existing code
 * 					 *Duplex read/write capability
 * 					 *Added custom PushBufferStream functionality from continual supply of byte[] packets
 *****************************************/

import java.awt.Dimension;
import java.io.IOException;

import javax.media.Buffer;
import javax.media.Control;
import javax.media.Format;
import javax.media.format.AudioFormat;
import javax.media.format.RGBFormat;
import javax.media.protocol.BufferTransferHandler;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.PushBufferStream;

public class LiveStream implements PushBufferStream, Runnable {

	protected ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW);
	protected int maxDataLength;
	protected byte [] data;
	protected Dimension size;
	protected RGBFormat rgbFormat;
	protected AudioFormat audioFormat;
	protected boolean started;
	public Thread thread;
	protected float frameRate = 20f;
	protected BufferTransferHandler transferHandler;
	protected Control [] controls = new Control[0];
	int marker = 0;
	int lastRead = 0;
	byte [][] rxbuffer;
	int rxbuffersize;
	boolean wrapped = false;

	protected boolean videoData = false;

	public LiveStream() {
		audioFormat = new AudioFormat(AudioFormat.MPEG,
				44100,
				16,
				2,
				AudioFormat.BIG_ENDIAN,
				AudioFormat.SIGNED,
				8,
				16000.0,
				Format.byteArray);

		rxbuffersize = 500;
		maxDataLength = 20000;/*UDPReceiver.MAX_PACKET_SIZE;*/
		rxbuffer = new byte[rxbuffersize][];

		thread = new Thread(this);
	}

	/***************************************************************************
	 * SourceStream
	 ***************************************************************************/

	public ContentDescriptor getContentDescriptor() {
		return cd;
	}

	public long getContentLength() {
		return LENGTH_UNKNOWN;
	}

	public boolean endOfStream() {
		return false;
	}

	/***************************************************************************
	 * PushBufferStream
	 ***************************************************************************/

	int seqNo = 1;
	double freq = 2.0;

	public Format getFormat() {
		if (videoData)
			return rgbFormat;
		else
			return audioFormat;
	}

	public void update(byte[] block){
		if(marker==rxbuffersize){
			wrapped = true;
			marker=0;
		}
		if((!wrapped) || (wrapped && marker!=lastRead)){
			rxbuffer[marker]=block;
			/** Debug-Ji
			if(block==null)
				System.out.println("WHY NULL?");
			**/
			marker++;
			//System.out.println("ADDED!+++++++++++++++++++++++++++++++++");
		}
		///** Debug-Ji
		//System.out.println("UPDATE: "+marker+", "+lastRead);
		//**/
	}

	public void read(Buffer buffer) throws IOException {
		synchronized (this) {
			///** Debug-Ji
			//System.out.println("DEBUG: READ: "+marker+", "+lastRead);
			//**/
			if(lastRead==rxbuffersize && marker!=rxbuffersize){
				wrapped = false;
				lastRead=0;
			}

			Object outdata = buffer.getData();
			if(lastRead==marker || rxbuffer[lastRead]==null){
				outdata = new byte[maxDataLength];
			}
			else{
				int temp = rxbuffer[lastRead].length;
				outdata = new byte[temp];
			}
			buffer.setData(outdata);
			buffer.setFormat( audioFormat );
			buffer.setTimeStamp( (long) seqNo * 1000000000 / 8 );
			if(lastRead!=marker && rxbuffer[lastRead]!=null)
				System.arraycopy(rxbuffer[lastRead], 0, outdata, 0, rxbuffer[lastRead].length);
			buffer.setSequenceNumber( seqNo );
			if(lastRead!=marker && rxbuffer[lastRead]!=null){
				buffer.setLength(rxbuffer[lastRead].length);
				//lastRead++;
			}
			else
				buffer.setLength(maxDataLength);
			if(lastRead!=marker)
				lastRead++;
			buffer.setFlags(32864);
			buffer.setHeader( null );
			seqNo++;
		}
	}

	public void setTransferHandler(BufferTransferHandler transferHandler) {
		synchronized (this) {
			this.transferHandler = transferHandler;
			notifyAll();
		}
	}

	public void start(boolean started) {
		synchronized ( this ) {
			this.started = started;
			if (started && !thread.isAlive()) {
				thread = new Thread(this);
				thread.start();
			}
			notifyAll();
		}
	}

	/***************************************************************************
	 * Runnable
	 ***************************************************************************/

	public void run() {
		while (started) {
			synchronized (this) {
				while (transferHandler == null && started) {
					try {
						wait(10);
					} catch (InterruptedException ie) {
						return;
					}
				} // while
			}

			if (started && transferHandler != null) {
				transferHandler.transferData(this);
				try {
					Thread.sleep(5);
				} catch (InterruptedException ise) {
					return;
				}
			}
		} // while (started)
	} // run

	// Controls

	public Object [] getControls() {
		return controls;
	}

	public Object getControl(String controlType) {
		try {
			Class<?>  cls = Class.forName(controlType);
			Object cs[] = getControls();
			for (int i = 0; i < cs.length; i++) {
				if (cls.isInstance(cs[i]))
					return cs[i];
			}
			return null;

		} catch (Exception e) {   // no such controlType or such control
			return null;
		}
	}
}
